package com.hd123.rumba.gwt.widget2.client.form;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;

/**
 * 对容器所包含的控件进行递归验证的工具类。 <br>
 * 本类的所有方法均为静态方法，和{@link RValidatable}的每个方法一一对应。<br>
 * 考虑一个较复杂的的控件结构（多层容器嵌套）中，假设每个容器都实现了RValidatable接口，
 * 则直接对最外层的容器调用RValidatable 接口方法即可实现递归验证，并不需要本类的存在。<br>
 * 但事实上并不是每个容器都实现了RValidatable接口，虽然Widget2的容器控件都做到了这一点，
 * 但GWT中大量的容器（ 例如VerticalPanel、
 * FlexTable等）都没有也不可能实现这个接口。这些未实现RValidatable的容器
 * 会阻断递归验证的链条，造成验证的遗漏。<br>
 * 本类就是为了解决这个问题产生的，以上这些未实现RValidatable的容器往往都实现了另一个接口：
 * {@link HasWidgets}
 * 。利用这一点，我们就能对容器进行递归探索，从而实现递归验证。本类的所有方法都以以下方式递归：<br>
 * 1. 对传入的HasWidgets进行枚举；<br>
 * 2. HasWidgets包含的控件如果是可验证的（即实现了RValidatable接口），则调用其验证方法并枚举下一个；<br>
 * 3.
 * HasWidgets包含的控件如果仍然是一个容器（即实现了HasWidgets接口），则对其递归的调用自身后，枚举下一下。
 * <p>
 * 应用场景1：<br>
 * 需要实现RValidatable的容器控件，例如RTabPanel，并不清楚自己会包含什么样的控件，
 * 这些控件很有可能是未实现RValidatable接口的， 这是就可以在实现RValidatable时调用本类的方法。
 * <p>
 * 应用场景2：<br>
 * 业务模块在最外层使用了非Widget2的容器，例如最外层是一个VerticalPanel，可以调用本类的方法进行验证。
 * 
 * 
 * @author LiQi
 * 
 */
public class RContainerValidator {

  public static void clearValidResults(HasWidgets container) {
    for (Iterator i = container.iterator(); i.hasNext();) {
      Object widget = i.next();
      if (widget instanceof RValidatable)
        ((RValidatable) widget).clearValidResults();
      else if (widget instanceof HasWidgets)
        clearValidResults((HasWidgets) widget);
    }
  }

  public static boolean isValid(HasWidgets container) {
    for (Iterator i = container.iterator(); i.hasNext();) {
      Object widget = i.next();
      if (widget instanceof RValidatable && !((RValidatable) widget).isValid())
        return false;
      else if (widget instanceof HasWidgets && !isValid((HasWidgets) widget))
        return false;
    }
    return true;
  }

  public static List getInvalidMessages(HasWidgets container) {
    List list = new ArrayList();
    for (Iterator i = container.iterator(); i.hasNext();) {
      Object widget = i.next();
      if (widget instanceof RValidatable)
        list.addAll(((RValidatable) widget).getInvalidMessages());
      else if (widget instanceof HasWidgets)
        list.addAll(getInvalidMessages((HasWidgets) widget));
    }
    return list;
  }

  public static boolean validate(HasWidgets container) {
    boolean valid = true;
    for (Iterator i = container.iterator(); i.hasNext();) {
      Object widget = i.next();

      if (widget instanceof Widget && !((Widget) widget).isVisible())
        continue;

      if (widget instanceof RValidatable)
        valid &= ((RValidatable) widget).validate();
      else if (widget instanceof HasWidgets)
        valid &= validate((HasWidgets) widget);
    }
    return valid;
  }
}
